package demo

import (
	"context"
	"sync"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

type Field = zapcore.Field

var mu sync.Mutex

type Logger interface {
	Debug(msg string)
	DebugC(ctx context.Context, msg string)
	Debugf(format string, args ...interface{})
	DebugfC(ctx context.Context, format string, args ...interface{})
	DebugW(msg string, keysAndValues ...interface{})
	DebugWC(ctx context.Context, msg string, keysAndValues ...interface{})
}

type zapLogger struct {
	zapLogger *zap.Logger
}

func (z *zapLogger) Debug(msg string) {
	z.Debug(msg)
}

func (z *zapLogger) DebugC(ctx context.Context, msg string) {
	z.DebugC(ctx, msg)
}

func (z *zapLogger) Debugf(format string, args ...interface{}) {
	z.Debugf(format, args...)
}

func (z *zapLogger) DebugfC(ctx context.Context, format string, args ...interface{}) {
	z.DebugfC(ctx, format, args...)
}

func (z *zapLogger) DebugW(msg string, keysAndValues ...interface{}) {
	z.DebugW(msg, keysAndValues...)
}

func (z *zapLogger) DebugWC(ctx context.Context, msg string, keysAndValues ...interface{}) {
	z.DebugWC(ctx, msg, keysAndValues...)
}

func New(opts *Options) *zapLogger {
	if opts == nil {
		opts = NewOptions(nil)
	}

	level, err := zap.ParseAtomicLevel(opts.Level)
	if err != nil {
		level = zap.NewAtomicLevelAt(zapcore.InfoLevel)
	}
	loggerConfig := zap.Config{
		Level: level,
	}

	l, err := loggerConfig.Build(zap.AddStacktrace(zapcore.PanicLevel))
	if err != nil {
		panic(err)
	}
	logger := &zapLogger{
		zapLogger: l.Named(opts.Name),
	}
	return logger
}

var (
	defaultLogger = New(NewOptions(nil))
)

func Init(opt *Options) {
	mu.Lock()
	defer mu.Unlock()
	defaultLogger = New(opt)
}

func Debug(msg string) {
	defaultLogger.Debug(msg)
}

func DebugC(ctx context.Context, msg string) {
	defaultLogger.DebugC(ctx, msg)
}

func Debugf(format string, args ...interface{}) {
	defaultLogger.Debugf(format, args...)
}

func DebugfC(ctx context.Context, format string, args ...interface{}) {
	defaultLogger.DebugfC(ctx, format, args...)
}

func DebugW(msg string, keysAndValues ...interface{}) {
	defaultLogger.DebugW(msg, keysAndValues...)
}

func DebugWC(ctx context.Context, msg string, keysAndValues ...interface{}) {
	defaultLogger.DebugWC(ctx, msg, keysAndValues...)
}
